package risoe.syslab.fhnew.controller.plugin;

/*
 * Copyright (c) 2012-2014, Technical University of Denmark (DTU)
 * All rights reserved.
 * 
 * The Flexhouse 2.0 platform ("this software") is licensed under the
 * BSD 3-clause license.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of DTU nor the names of its contributors may be used to
 *     endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE TECHNICAL UNIVERSITY OF DENMARK BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.rmi.RemoteException;
import java.util.HashMap;

import risoe.syslab.fhnew.common.SystemConstants.DeviceType;
import risoe.syslab.fhnew.config.ActuatorConfig;
import risoe.syslab.fhnew.config.BuildingConfig;
import risoe.syslab.fhnew.config.SensorConfig;
import risoe.syslab.fhnew.controller.ControllerConfig;
import risoe.syslab.fhnew.controller.PluginController;
import risoe.syslab.fhnew.hw.Actuator;
import risoe.syslab.fhnew.hw.Sensor;
import risoe.syslab.model.CompositeMeasurement;

public class AntiFrostController extends PluginController{
	private File outFile;
	private PrintWriter outStream;
	private boolean heatersOn = true;

	private HashMap<String, SensorTracker> mTemperatureTrackers;
	private class SensorTracker{
		public double mValue = 0.0;
		public boolean mUpdated = false;
	}

	public static void main(String[] args) {
		try {
			String configFile = args.length > 0? args[0]: null;
			new AntiFrostController("AntiFrostController", "jahsad", configFile);
		} catch (RemoteException e) {
			// RMI Connection was unsuccessful 
			System.out.println("RMI Error: "+e.getMessage());
			System.exit(0);
		} catch (InstantiationException e) {
			// Controller name was already taken, or one of the requested permissions was already used by
			// another plugincontroller
			System.out.println("Argument Error: "+e.getMessage());
			System.exit(0);
		}
	}

	public AntiFrostController(String name, String owner, String cfgfile)
			throws RemoteException, InstantiationException {
		super(name, owner, cfgfile);
	}

	@Override
	public ControllerConfig supplyControllerConfig(ControllerConfig config) {
		config.addControlledDeviceType(DeviceType.PowerControlledHeater);
		config.addTypeSubscription(DeviceType.Temperature);
		config.addTypeSubscription(DeviceType.WindDirection);
		config.addTypeSubscription(DeviceType.WindSpeed);
		config.addTypeSubscription(DeviceType.Motion);
		config.addTypeSubscription(DeviceType.Flow);
		config.addTypeSubscription(DeviceType.FlowTemperature);
		config.addTypeSubscription(DeviceType.ReturnFlowTemperature);
		config.addTypeSubscription(DeviceType.Power);

		return config;
	}

	@Override
	public void initialStateReceived(Actuator[] actuators) {
		System.out.println("Initialized...");

		try {
			outFile = new File("tmp/AntiFrost.csv");
			outFile.createNewFile();
			outStream = new PrintWriter(outFile);
			outStream.write("Time, Name, Value\n");
			
			outStream.flush();
			
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("Error opening log file "+e.getMessage());
		}

		mTemperatureTrackers = new HashMap<String, SensorTracker>();
		for (SensorConfig sensor : getBuildingConfig().getAllSensors()){
			if (sensor.getType() == DeviceType.Temperature && !sensor.getName().contains("Outside")){
				System.out.println("Put sensor: "+sensor.getName());
				mTemperatureTrackers.put(sensor.getName(), new SensorTracker());
			}
		}

		setHeaters(true);
	}

	private void setHeaters(boolean on){
		heatersOn = on;
		BuildingConfig config = getBuildingConfig();

		for (ActuatorConfig act : config.getAllActuators()){
			if (act.getType() == DeviceType.PowerControlledHeater){
				setActuator(act.getName(), new CompositeMeasurement(on? 1.0: 0.0));
			}
		}
	}

	@Override
	public void sensorUpdated(Sensor s) {
		if (s.getType() == DeviceType.Temperature && !s.getName().contains("Outside")){
			SensorTracker trackerToUpdate = mTemperatureTrackers.get(s.getName());
			if (trackerToUpdate != null){
				trackerToUpdate.mValue = s.getValue().value;
				trackerToUpdate.mUpdated = true;
			}
			else{
				System.out.println("Unknown Tracker: "+s.getName());
			}

			// Check if all the sensors have been updated
			boolean allUpdated = true;
			for (SensorTracker tracker : mTemperatureTrackers.values()){
				if (!tracker.mUpdated){
					allUpdated = false;
					break;
				}
			}

			if (allUpdated){
				// Compute average temperature in room
				double sum = 0;
				for (SensorTracker tracker : mTemperatureTrackers.values()){
					sum += tracker.mValue;

					// Clear the updated flags
					tracker.mUpdated = false;
				}
				double average = sum/mTemperatureTrackers.size();

		//		outStream.write(System.currentTimeMillis() + ", temp_average ,"+average + "\n");
		//		outStream.flush();
			

				if (average >= 28.0 && heatersOn){
					System.out.println("27 degrees reached! Turning off all heaters...");
					setHeaters(false);
				}
				else if (average <= 5.0){
					System.out.println("5 degrees reached! Stopping "+getName());
					System.exit(0);
				}
				
				System.out.println("New average: "+average);
			}
		}
		
	
				outStream.write(System.currentTimeMillis() + ","+s.getName() + ","+s.getValue().value + "\n");
				outStream.flush();
		
	}
}
